#include "Tetris.h"

Tetris *tetris = NULL;



Tetris::Tetris()
{
	printf("Constructor Tetris\n");
	srand((unsigned int)time(NULL));
		numBlocks = 0;
	this->texture[0] = 13;

	printf("Loading tectures\n");

	//this->loadTextures();

	printf("Creating window\n");

	this->window = new OpenglWindow("Tetris",640,480, &windowHandler);
	
	tetris = this;
	this->quit = false;

	printf("Creating blok\n");
	this->createNewBlok();

	printf("Creating light\n");
	const GLfloat	ambientLight[] = { 0.5f, 0.5f, 1.0f, 1.0f };
	glLightfv(GL_LIGHT1, GL_AMBIENT, ambientLight);

	printf("Showing window\n");
	this->window->show();

	printf("End of constructor\n");
	
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);
	glEnable(GL_NORMALIZE);
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_SMOOTH);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


}

void Tetris::mainLoop()
{
	MSG msg;
	try {
		while ( !this->quit )
		{
			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
			{
				if (msg.message == WM_QUIT)
					this->quit = true;
				else
				{
					TranslateMessage(&msg);
					DispatchMessage(&msg);
				}
			} else {
				this->tick();
			}
		}
	}
	catch ( OpenglWindowException &ex )	{
		MessageBox(NULL,ex.message,TEXT("OpenglWindow error"), MB_OK|MB_ICONERROR);
		delete[] this;
	}
	catch ( ... ) {
		MessageBox(NULL, TEXT("Error."),TEXT("OpenglWindow error"), MB_OK|MB_ICONERROR);
		delete[] this;
	}
}

void Tetris::setDebugMode(int mode)
{
	this->debugMode = mode;
}
GLuint Tetris::loadTexture(Image *image)
{
	GLuint textureId;
	glGenTextures(1, &textureId);
	glBindTexture(GL_TEXTURE_2D, textureId);
	glTexImage2D(GL_TEXTURE_2D,
		0,
		GL_RGB,
		image->width,
		image->height,
		0,
		GL_RGB,
		GL_UNSIGNED_BYTE,
		image->pixels);
	return textureId;
}
bool Tetris::loadTextures()
{
	Image *image = loadBMP("test.bmp");
	texture[0] = loadTexture(image);
	delete image;
	return true;
}
void Tetris::createNewBlok()
{
	printf("(%0d) Creating new blok\n",numBlocks);

	if (numBlocks>=50)
	{
		MessageBox(NULL,TEXT("This shouldn't happen, what did you do?"),TEXT("CRITICAL ERROR"),MB_OK|MB_ICONERROR);	
		exit(0);

	}

	tblokken[numBlocks] = TetrisBlok(this->random(6));
	activeBlok = &tblokken[numBlocks];
	
	activeBlok->setPos(0,50,0);

	numBlocks++;
}

bool Tetris::collisionDetect(bool a, bool b)
{
	float offX=0, offY=0;
	
	for (int i=0;i<4;i++)
	{	// loop trough all the blocks in our active blok
		offX = activeBlok->blokken[i].fX;
		offY = activeBlok->blokken[i].fY;

		if (a && !b) // links check
			offX -= activeBlok->blokSize*2;
		if (!a && !b) // right check
			offX += activeBlok->blokSize*2;
		if (a && b)	// below check
			offY -= activeBlok->blokSize*2;
		if (!a && b) // up^check
			offY += activeBlok->blokSize*2;
		
						// borders! only bottom for now
		if (offY < 0) 
			return true;
		
		// loop trough all blocks on the screen ,except the active one
		for (int j=0;j<numBlocks-1;j++)
		{
			// loop trough all the blocks of the block
			for (int k=0; k<4;k++)
			{
				if ((tblokken[j].blokken[k].fX == offX) && (tblokken[j].blokken[k].fY == offY))
					return true;

				
			}
		}
	}
	return false;

}

int Tetris::random(int max)
{
	return rand()%(max+1);
}
void Tetris::draw3D()
{
	static float frassmes = 0;

	frassmes ++;

	if (frassmes == 1000)
	{
		frassmes = 0;
		
		if (!this->collisionDetect(true, true) /*&& this->activeBlok->drop()*/)
		{
			this->activeBlok->drop();
		}
		else
			this->createNewBlok();

	}


	glBegin(GL_QUADS);
		for (int i=0; i < numBlocks; i++)
		{
			if (tblokken[i].active)
			{
				this->tblokken[i].draw();
			}

		}
	glEnd();
}
void Tetris::draw2D()
{

}
void Tetris::drawTest()
{

}
void Tetris::draw3DGrid()
{
	for(float i = -500; i <= 500; i += 5)
	{
		glBegin(GL_LINES);
			glColor3f(0.1f, 0.1f, 0.1f);						
			glVertex3f(-500, 0, i);					
			glVertex3f(500, 0, i);
			glVertex3f(i, 0,-500);							
			glVertex3f(i, 0, 500);
		glEnd();
	}

}
void Tetris::drawFloor()
{
	//glColor3f(0.1f, 0.1f, 0.1f);
	static const float floorSize=20.0f;
	static const float floorY = -1.0f;

	glBegin(GL_QUADS);
		glVertex3f(-floorSize,floorY,floorSize);
		glVertex3f(-floorSize,floorY,-floorSize);
		glVertex3f(floorSize,floorY,-floorSize);
		glVertex3f(floorSize,floorY,floorSize);
	glEnd();
}
void Tetris::reflectiontest()
{
	glEnable(GL_STENCIL_TEST);
	glColorMask(0, 0, 0, 0);
	glDisable(GL_DEPTH_TEST);
	glStencilFunc(GL_ALWAYS, 1, 1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);

	this->drawFloor();

	glColorMask(1, 1, 1, 1);
	glEnable(GL_DEPTH_TEST);
	glStencilFunc(GL_EQUAL, 1, 1);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

	// reflect render
	glPushMatrix();
	glScalef(1, -0.5, 1);
	glTranslatef(0, 4.5f, 0);
	
	this->draw3D();

	glPopMatrix();
	
	glDisable(GL_STENCIL_TEST);

	glEnable(GL_BLEND);

	// floor kleur
	glColor4f(0.01f,0.01f,0.01f, 0.85f);
	this->drawFloor();
	glDisable(GL_BLEND);	
}

void Tetris::render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
	
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0.0f,-10.0f,-100.0f);
	
	
	// we can start drawing now
	static float angle = -25.0f;
	static float incrementer = 0.002f;
	angle+= incrementer;
	if (angle > 25) incrementer = -incrementer;
	if (angle < -25) incrementer = -incrementer;

	if (angle > 360) angle-= 360;	
	glRotatef(angle,10.0f, 1.0f, 5.0f);


	//this->draw3DGrid();
	//this->drawTest();
	
	this->draw3D();

	this->reflectiontest();
	//this->draw2D();



}
void Tetris::tick()
{
	this->render();
	
	this->window->swapBuffers();
}
void Tetris::keyPress(int key, bool down)
{
	switch (key)
	{
	case VK_LEFT:
		if ( !this->collisionDetect(true,false))
			this->activeBlok->moveLeft();
		break;

	case VK_RIGHT:
		if ( !this->collisionDetect(false,false))
			this->activeBlok->moveRight();
		break;

	case VK_UP:
		if ( !this->collisionDetect(false,true))
			this->activeBlok->rotate(false);
		break;

	case VK_DOWN:
		if (!this->collisionDetect(true, true))
			this->activeBlok->drop();
		break;

	case VK_ESCAPE:
		tetris->quit = true;
		break;
	}
}

LRESULT windowHandler(HWND hWnd, UINT uMsg,WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_CLOSE:
		{
			PostQuitMessage(0);
			return 0;
		}
	case WM_SIZE:
		{
			tetris->window->resize(LOWORD(lParam), HIWORD(lParam));
	//		tetris->tick();
			break;
		}

	case WM_MOVE:
		{
	//		tetris->tick();
			break;
		}

	case WM_KEYDOWN:
		{
			tetris->keyPress((int)wParam, true);
			break;
		}

	case WM_KEYUP:
		{
			//tetris->keyPress(wParam, false);
		}
	}
	
	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Tetris::~Tetris()
{
	this->destroy();
}
void Tetris::destroy()
{
	this->window->destroy();
	this->window = NULL;

}
